﻿/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is KazeOS Framework.
  
  The Initial Developer of the Original Code is
  ALCARAZ Marc (aka eKameleon) <ekameleon@gmail.com>.
  Portions created by the Initial Developer are Copyright (C) 2004-2010
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
*/

package evisio.net 
{
    import evisio.ApplicationID;
    import evisio.managers.IStateManager;
    import evisio.model.ModelList;
    import evisio.states.StateList;
    import evisio.states.ask.AskState;
    import evisio.states.authentification.AuthentificationState;
    import evisio.vo.UserVO;
    
    import system.Strings;
    import system.eden;
    import system.events.ActionEvent;
    
    import vegas.CoreObject;
    import vegas.events.NetServerEvent;
    import vegas.ioc.factory.ECMAObjectFactory;
    import vegas.managers.ProtectorManager;
    import vegas.models.CoreModelObject;
    import vegas.net.NetServerConnection;
    import vegas.net.NetServerInfo;
    
    import flash.events.NetStatusEvent;
    import flash.net.NetStream;
    import flash.net.Responder;
    import flash.system.Capabilities;
    
    /**
     * Invoked when a NetServerConnection notify events.
     */
   public class NetServerConnectionListener extends CoreObject
   {
        /**
         * Creates a new NetServerConnectionListener instance.
         */
        public function NetServerConnectionListener()
        {
        
        }
        
        /**
         * Indicates the NetServerConnection reference.
         */
        public var connection:NetServerConnection ;
        
        /**
         * The IoC factory reference.
         */
        public var factory:ECMAObjectFactory ;
        
        /**
         * The locale object. This object contains all information in the localization of this instance.
         */
        public var locale:Object ;
        
        /**
         * The protector manager reference.
         */
        public var protectorManager:ProtectorManager ;
        
        /**
         * The state manager reference.
         */
        public var stateManager:IStateManager ;
        
        /**
         * Indicates the NetServerConnection reference.
         */
        public var stratus:NetServerConnection ;
        
        /**
         * The stratus url value.
         */
        public var stratusUrl:String ;
        
        /**
         * Handles the event when the connection is accepted.
         */
        public function accept( e:NetServerEvent ):void 
        {
           logger.debug( this + " accept : " + e.info.description ) ;
        }
        
        /**
         * Handles the event when the connection is closed.
         */
        public function close( e:NetServerEvent ):void 
        {
            logger.debug( this + " close : " + e.info ) ; 
            if ( stratus != null && stratus.connected )
            {
                stratus.close() ;
            }
            if ( factory != null )
            {
                var model:CoreModelObject ;
                model = factory.getObject( ModelList.USER ) ;
                if ( model != null && model.getCurrentVO() != null )
                {
                    model.clear() ;
                }
                model = factory.getObject( ModelList.GUEST ) ;
                if ( model != null && model.getCurrentVO() != null )
                {
                    model.clear() ;
                }
            }
        }
         
        /**
         * Handles the event when the connection is started.
         */
        public function finish( e:ActionEvent ):void 
        {
           logger.debug( this + " finish" ) ;
           if ( protectorManager != null )
           {
                protectorManager.enabled = false ;
           }
        } 
        
        /**
         * Handles the event when the connection is rejected.
         */
        public function reject( e:NetServerEvent ):void 
        {
            logger.warn( this + " reject : " + e.info ) ; 
             if ( factory != null )
            {
                var authentification:AuthentificationState = factory.getObject( StateList.AUTHENTIFICATION_STATE ) as AuthentificationState ;
                if ( authentification != null && locale != null )
                {
                    var info:NetServerInfo = e.info as NetServerInfo ;
                    try
                    {
                       authentification.message = Strings.format( locale.connection_reject , info.application.message ) ;    
                    }
                    catch( er:Error )
                    {
                        authentification.message = Strings.format( locale.connection_reject , info.description  )  ;
                    }
                }
            }
        }
        
        /**
         * Handles the event when the connection indicates a status wich change.
         */
        public function status( e:NetStatusEvent ):void 
        {
            logger.debug( this + " status : " + eden.serialize( e.info ) ) ;
        }
        
        /**
         * Handles the event when the connection is started.
         */
        public function start( e:ActionEvent ):void 
        {
           logger.debug( this + " start" ) ;
           if ( protectorManager != null )
           {
                protectorManager.enabled = true ;
           }
        }        
        
        ////////////////////// server callback methods
        
        /**
         * Indicates a buzzy guest invitation.
         */
        public function buzzy( to:String ):void
        {
            var ask:AskState = factory.getObject( StateList.ASK_STATE ) as AskState ;
            if ( ask != null && ask.locale != null )
            {
                ask.message = Strings.format( ask.locale.buzzy  )  ;
            }
            if ( protectorManager != null && protectorManager.enabled )
            {
                protectorManager.enabled = false ;
            }
        }
        
        /**
         * Close the current session
         */
        public function closeSession():void
        {
            if ( factory != null )
            {
                var model:CoreModelObject = factory.getObject( ModelList.GUEST ) ;
                if ( model != null )
                {
                    var guest:UserVO = model.getCurrentVO() as UserVO ;
                    if ( guest != null )
                    {
                        model.clear() ;
                        // TODO display in the ask field the message to notify the disconnect of the guest !!!!!
                    }
                    else
                    {  
                        logger.warn(this + " failed to close the session, no guest register.") ;
                    }
                }
                else
                {
                    logger.warn(this + " failed to close the session, unknow guest model.") ;
                }
            }
        }
        
        /**
         * Init the user of the application.
         */
        public function createUser( user:UserVO , stratusKey:String = null ):void
        {
            logger.info( this + " init user : " + user + " : " + stratusKey ) ;
            if ( factory != null && user != null  )
            {
                var model:CoreModelObject = factory.getObject( ModelList.USER ) ;
                if ( model != null )
                {
                    model.setCurrentVO( user ) ;
                    if ( stratus != null && stratus.connected == false && stratusUrl != null )
                    {
                        var url:String = Strings.format( stratusUrl , stratusKey ) ;
                        logger.info( this + " connect stratus : " + url + " :: " + Capabilities.version) ;
                        stratus.connect( url ) ; 
                    }
                    else
                    {  
                        logger.warn(this + " failed to connect the stratus serveur.") ;
                    }
                }
            }
        }          
        
        /**
         * Finalize the invitation sending by the user of the application.
         */
        public function finishInvitation( user:UserVO , peerID:String ):void
        {
            logger.info( this + " finish invitation from " + user + " with the peerID:" + peerID) ;
            if ( factory != null && user != null  )
            {
                var model:CoreModelObject = factory.getObject( ModelList.GUEST ) ;
                if ( model != null )
                {
                    model.setCurrentVO( user ) ;
                    if ( stratus != null && stratus.connected )
                    {
                        
                        model = factory.getObject( ModelList.USER ) ;
                        user  = model.getCurrentVO() as UserVO ;
                        
                        var streamIn:StreamInExpert = factory.getObject( ApplicationID.STREAM_IN_EXPERT ) as StreamInExpert ;
                        if ( streamIn != null )
                        {
                            streamIn.netStream = new NetStream( stratus.connection , peerID ) ; 
                            _resultRespondInvitation(true) ;
                            streamIn.netStream.play( user.streamID ) ;
                        }
                        else
                        {
                            logger.warn(this + " the stream in can't bet created the expert don't exist in the factory.") ;
                        }
                        
                        var streamOut:StreamOutExpert = factory.getObject( ApplicationID.STREAM_OUT_EXPERT ) as StreamOutExpert ;
                        if ( streamOut != null )
                        {
                            streamOut.netStream.publish( user.streamID ) ;
                        }
                        else
                        {
                            //
                        }
                        
                    }    
                    else
                    {
                        logger.warn(this + " the stream in can't bet created the stratus connection don't exist or is disconnected now.") ;            
                    }
                }
                else
                {
                    logger.warn(this + " can't initialize the guest user in this model, the model reference don't exist.") ;
                }
            }
        }
        
        /**
         * Indicates if the user has a guest.
         */
        public function hasGuest():Boolean
        {
            if ( factory != null )
            {
                var model:CoreModelObject = factory.getObject( ModelList.GUEST ) ;
                if ( model != null )
                {
                    return ( model.getCurrentVO() as UserVO ) != null ;
                }
            }
            return false ;
        }
          
        /**
         * The user receive a new invitation from the FMS server.
         */
        public function receiveInvitation( user:UserVO , peerID:String ):void
        {
            logger.info( this + " receive invitation from " + user + " with the peerID:" + peerID) ;
            
            if ( factory != null && user != null  )
            {
                var model:CoreModelObject ;
                
                model = factory.getObject( ModelList.GUEST ) ;
                if ( model != null )
                {
                    model.setCurrentVO( user ) ;
                }
                
                var streamIn:StreamInExpert = factory.getObject( ApplicationID.STREAM_IN_EXPERT ) as StreamInExpert ;
                streamIn.netStream          = new NetStream( stratus.connection , peerID ) ;
                streamIn.netStream.play( user.streamID ) ;
                                
                var streamOut:StreamOutExpert = factory.getObject( ApplicationID.STREAM_OUT_EXPERT ) as StreamOutExpert ;
                if ( streamOut != null )
                {
                    streamOut.netStream.publish( user.streamID ) ;
                }
                
                var to:String = user.id ;
                
                if( to != null && connection != null && connection.connected && stratus != null && stratus.connected )
                {
                    var responder:Responder = new Responder( _resultRespondInvitation, _statusRespondInvitation ) ;
                    
                    logger.info( this + " respond Invitation from " + user + " to:" + to + " with the peerID:" + stratus.nearID) ;
                    
                    connection.call("respondInvitation", responder , to, stratus.nearID ) ;
                }
                else
                {
                    logger.error(this + " respond the invitation failed, the connections are disconnected or don't exist") ;
                }
            }
        }
        
        /**
         * @private
         */
        private function _resultRespondInvitation( result:* ):void
        {
            if ( result is Boolean && result == true )
            {
                var user:UserVO ;
                var model:CoreModelObject = factory.getObject( ModelList.USER ) ;
                if ( model != null )
                {
                    user = model.getCurrentVO() as UserVO ;
                }
                logger.info(this + ": " + user + " valid the invitation : " + result ) ;
                
                if ( stateManager != null )
                {
                    stateManager.currentState = StateList.CHAT_STATE ;
                }
                
            }
            else
            {
                logger.warn(this + " respond invitation failed, result:" + result + ", the to user is now unknow or disconnected.") ;
            }
        }
        
        /**
         * @private
         */
        private function _statusRespondInvitation( info:Object ):void
        {
            logger.warn(this + " respond invitation status : " + eden.serialize(info)) ;
        }
    }
}
